<?php
/**
 * +----------------------------------------------------------------------
 * | Author: 罗极
 * +----------------------------------------------------------------------
 * | Description: App.php
 * +----------------------------------------------------------------------
 * | User: Administrator Date: 8/20/ 0020 Time: 15:05
 * +----------------------------------------------------------------------
 */
namespace Framework\App;

use Framework\Config\Constant\DefaultKey;
use Framework\Config\Config;
use Framework\Event\ControllerListener;
use Framework\Event\TestListener;
use Framework\Response\{HttpStatusResponse,NotFoundResponse};
use Framework\Log\Log;
use Framework\Router\Router;
use Framework\View\Abstracts\ViewAbstract;
use Framework\View\{Error404View,Error50xView,HtmlView,ViewConfig};

class App
{
    public static function run(array $config)
    {

        /**@var $configObj  \Framework\Config\Config**/
        $configObj = Config::getInstance();
        $configObj->batchSet($config);

        if($devConfPath = $configObj->get(DefaultKey::DevConf)) {
            $configObj->batchSet(require $devConfPath);
        }

        define('DEBUG', $configObj->get(DefaultKey::Debug));

        if(DEBUG) {
            ini_set('display_errors', true);
            error_reporting(E_ALL);
        } else {
            ini_set('display_errors', false);
            error_reporting(0);
        }

        register_shutdown_function('Framework\App\Halt::shutdown');

        if(!file_exists($routerPath = $configObj->get(DefaultKey::RouterPath))) {
            throw new \RuntimeException('全局路由配置文件找不到');
        }

        define('REQUEST_METHOD', $_SERVER['REQUEST_METHOD']);

        require $routerPath;



        /**@var $requestRouterObj \Framework\Router\Abstracts\RequestRouter**/
        try {
            // 初始化配置
            $requestRouterObj   = Router::forward($_SERVER['REQUEST_URI']); // PHP_SELF /index.php/index/index
            $mainPath           = BASE_PATH.DS.$configObj->get(DefaultKey::MainDirName);
            $appVer             = $configObj->get(DefaultKey::AppVer);
            $subControllerPath  = $requestRouterObj->getModuleWithSuffix().DS
                                 .$configObj->get(DefaultKey::ControllerDirName).DS
                                 .$requestRouterObj->getControllerWithSuffix();
            $requestContollerPath = $mainPath.DS.$appVer.DS.$subControllerPath.'.php';

            ViewConfig::$suffix     = $configObj->get(DefaultKey::ViewSuffix);
            ViewConfig::$actionName = $requestRouterObj->getAction();
            ViewConfig::$controllerName = $requestRouterObj->getController();
            ViewConfig::$moduleDirName  = $requestRouterObj->getModule();
            ViewConfig::$viewDirName    = $configObj->get(DefaultKey::ViewDirName);
            ViewConfig::$entryDirName   = $mainPath.DS.$appVer.DS;

            define('Module', $requestRouterObj->getModule());
            define('Controller', $requestRouterObj->getController());
            define('Action', $requestRouterObj->getAction());

            if(!file_exists($requestContollerPath)) {
                throw new \Framework\Router\Exception\NotFoundException(sprintf(
                        '请求类文件找不到:[%s]',
                        $appVer.DS.$subControllerPath.'::'.$requestRouterObj->getAction()
                    ));
            }
        } catch(\Framework\Router\Exception\NotFoundException $e) {
            Error404View ::trigger($e->getMessage(), $configObj->get(DefaultKey::Default404Path));
        } catch(\Exception $e) {
            Error50xView::trigger($e->getMessage(), $configObj->get(DefaultKey::Default50xPath));
        }

        try{
            define('REQUEST_CONTROLLER_FILE', $requestContollerPath);
            require $requestContollerPath;

            $namespace = $configObj->get(DefaultKey::MainDirName)
                        .'\\'.$appVer
                        .'\\'.$requestRouterObj->getModuleWithSuffix()
                        .'\\'.$configObj->get(DefaultKey::ControllerDirName)
                        .'\\'.$requestRouterObj->getControllerWithSuffix();

            $viewPath  = BASE_PATH.DS.$configObj->get(DefaultKey::MainDirName)
                        .DS.$appVer
                        .DS.$requestRouterObj->getModuleWithSuffix()
                        .DS.$configObj->get(DefaultKey::ViewDirName);

            $actionViewPath = $viewPath.DS.$requestRouterObj->getController()
                            .DS.$requestRouterObj->getAction().'.'.$configObj->get(DefaultKey::ViewSuffix);
            $error404ViewPath = $viewPath.DS.$configObj->get(DefaultKey::ErrorDirName)
                            .DS.$configObj->get(DefaultKey::File404Name);

            $error50xViewPath = $viewPath.DS.$configObj->get(DefaultKey::ErrorDirName)
                            .DS.$configObj->get(DefaultKey::File50xName);

            if(!class_exists($namespace)) {
                throw new \Framework\App\Exception\NotFoundException(sprintf(
                    'Class不存在 : [%s]',
                    $namespace
                ));
            }

            $controllerProxyClass = new ControllerProxy(new $namespace);

            ob_start();
            $classReturn = call_user_func([$controllerProxyClass, $requestRouterObj->getActionWithSuffix()]);

            if(is_string($classReturn)) {
                echo $classReturn;
            }

            if($classReturn instanceof ViewAbstract) {
                $classReturn->show();
            }

            $outBuffer = ob_get_contents();
            ob_end_clean();
            // todo 拿到ob 可以方便缓存

            echo $outBuffer;

            // todo 写log 代理
            //Log::write('test log', BASE_PATH.DS.'Log');


        } catch(\Framework\Controller\Exception\NonCallableException $e) {
            Error50xView::trigger($e->getMessage(), $error50xViewPath);
        } catch (\Framework\Controller\Exception\NotFoundException $e) {
            Error404View ::trigger($e->getMessage(), $error404ViewPath);
        } catch(\Framework\View\Exception\NotFoundException $e) {
            Error50xView::trigger($e->getMessage(), $configObj->get(DefaultKey::Default50xPath));
        } catch(\Exception $e) {
            Error50xView::trigger($e->getMessage(), $configObj->get(DefaultKey::Default50xPath));
        } finally {

            if(DEBUG) { // 调试用
                echo "<p>".(microtime(true) - APP_START_TIME).".S</p>";
            }
        }


    }
}